/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.totoland.web.controller.printing;

import com.totoland.db.entity.StudentInfo;
import com.totoland.web.controller.BaseController;
import com.totoland.web.service.GennericService;
import com.totoland.web.service.StudentInfiService;
import com.totoland.web.utils.MessageUtils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.text.AttributedString;
import java.util.Date;
import javax.annotation.PostConstruct;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import javax.servlet.ServletContext;
import net.sourceforge.barbecue.Barcode;
import net.sourceforge.barbecue.BarcodeFactory;
import net.sourceforge.barbecue.BarcodeImageHandler;
import org.apache.commons.io.FileUtils;
import org.primefaces.event.CaptureEvent;
import org.primefaces.model.CroppedImage;
import org.primefaces.model.StreamedContent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author totoland
 */
@ManagedBean
@ViewScoped
public class CaptureInfoController extends BaseController {

    private static final long serialVersionUID = 1007114614954046849L;

    private static final Logger LOGGER = LoggerFactory.getLogger(CaptureInfoController.class);

    private static final String FONT_NAME = "IrisUPC";
    private static final String TEMP_PHOTO_CAM = "/temp/photocam/";
    private static final Font FONT14 = new Font(FONT_NAME, Font.BOLD, 14 * 4);
    private static final Font FONT13 = new Font(FONT_NAME, Font.BOLD, 13 * 4);
    private static final String IMAGE_TEMPLATE = "template.jpg";
    private String filename = "/temp/photocam/no-avatar1.png";

    private StreamedContent regPhoto;

    private CroppedImage croppedImage;

    private String newImageName = "/temp/photocam/no-avatar.png";

    private String searching;

    private boolean allowCapture = false;

    private boolean allowCrop = false;

    private boolean allowCombine = false;

    private StudentInfo studentInfo;

    private String maxSize = "160,199";//"136,180"
    private String minSize = maxSize;
//    private String initialCoords="35,40,150,70";
    private String initialCoords = "70,75,300,125";

    @ManagedProperty("#{studentInfoService}")
    private StudentInfiService studentInfoService;

    @ManagedProperty("#{gennericService}")
    private GennericService<StudentInfo> gennericService;

    @PostConstruct
    public void init() {

        LOGGER.trace("init...");

    }

    public void reset() {
        filename = "/temp/photocam/no-avatar1.png";

        regPhoto = null;

        croppedImage = null;

        newImageName = "/temp/photocam/no-avatar.png";

        allowCapture = false;

        allowCrop = false;

        allowCombine = false;

        studentInfo = null;

    }

    public void searchInfo() {

        if (searching == null || searching.isEmpty()) {
            addError("กรุณาระบุรหัสนักศึกษา"); 
            reset();
            return;
        }

        reset();

        LOGGER.info("Search wording : {}", searching);

        if (searching != null && !searching.isEmpty()) {

            studentInfo = studentInfoService.getStudentInfo(searching);
            
            if (studentInfo == null) {
                addError("ไม่พบรหัสนักศึกษา");
                reset();
                return;
            }

            allowCapture = studentInfo.getImagePath() == null;

            if (!allowCapture) {
                addError("มีภาพถ่ายนักศึกษาในระบบแล้ว!!");
            }
        }

        LOGGER.debug("allowCrop : {}", allowCrop);

    }

    public void saveWithOutCapture(){
        updateDateStudentCapture();
    }
    
    public void save() {

        String moveTo = MessageUtils.getConfig("path.file.download") + searching + ".png";

        LOGGER.debug("Move To : {}", moveTo);

        try {
            if (croppedImage != null) {
                FileUtils.moveFile(new File(getPathImage() + searching + "_crop.png"), new File(moveTo));
            } else {
                addError("กรุณาถ่ายภาพก่อนกด ส่งข้อมูล");
            }
        } catch (Exception ex) {
            LOGGER.error("Move File Error : ", ex);
        }

        updateDateStudentCapture();

    }
    
    private boolean editMode = false;
    
    public void goToEdit(){
        editMode = true;
    }
    
    public void goToCancel(){
        editMode = false;
    }
    
    public void updateInfo(){
        try{
            gennericService.edit(studentInfo);
            addInfo("แก้ใขข้อมูลเสร็จสิ้น!!");
        }catch(Exception ex){
            LOGGER.error("Update error : ",ex);
            addError("ไม่สามารถแก้ใขข้อมูลได้!!");
        }
        goToCancel();
    }

    private String combineImage(String imageCrop) throws Exception {

        LOGGER.debug("imageCrop : {}", imageCrop);

        File path = new File(getPathTemplate());
        File pathImageCrop = new File(getPathImage());
        //Barcode
        String barCode = createBarCode(studentInfo.getStudentID());

        // load source images
        BufferedImage image = ImageIO.read(new File(path, IMAGE_TEMPLATE));
        BufferedImage _overlay = ImageIO.read(new File(pathImageCrop, imageCrop));

        int _w = _overlay.getWidth();
        int _h = _overlay.getHeight();
        BufferedImage overlay = new BufferedImage(_w*2, _h*2, BufferedImage.TYPE_INT_ARGB);
        AffineTransform at = new AffineTransform();
        at.scale(2.0, 2.0);
        AffineTransformOp scaleOp
                = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
        overlay = scaleOp.filter(_overlay, overlay);

        BufferedImage imageBarCode = ImageIO.read(new File(barCode));

        // create the new image, canvas size is the max. of both image sizes
        int w = Math.max(image.getWidth(), overlay.getWidth());
        int h = Math.max(image.getHeight(), overlay.getHeight());

        //image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

        // paint both images, preserving the alpha channels
        Graphics g = combined.getGraphics();
        setGraphics(g, image, overlay, imageBarCode, studentInfo, FONT14);

        // Save as new image
        File newImage = new File(pathImageCrop, "combined_" + imageCrop);
        ImageIO.write(combined, "PNG", newImage);

        File newImageNoBG = new File(pathImageCrop, "nobg_" + imageCrop);
        image = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
        g = image.getGraphics();
        setGraphics(g, image, overlay, imageBarCode, studentInfo, FONT14);

        ImageIO.write(image, "PNG", newImageNoBG);

        //ByteArrayOutputStream os = new ByteArrayOutputStream();
        //ImageIO.write(image, "png", os);
        LOGGER.debug("newImage : " + newImage.getPath());

        setCombindWithOutBG(TEMP_PHOTO_CAM + "nobg_" + imageCrop);

        return TEMP_PHOTO_CAM + "combined_" + imageCrop;
    }

    private String combindWithOutBG;

    private String getRandomImageName() {
        int i = (int) (Math.random() * 10000000);
        return String.valueOf(i);
    }

    public String getFilename() {
        return filename;
    }

    public CroppedImage getCroppedImage() {
        return croppedImage;
    }

    public void setCroppedImage(CroppedImage croppedImage) {
        this.croppedImage = croppedImage;
    }

    public String getNewImageName() {
        return newImageName;
    }

    public void setNewImageName(String newImageName) {
        this.newImageName = newImageName;
    }

    public String getPathTemplate() {
        ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
        return servletContext.getRealPath("") + File.separator + "temp" + File.separator;
    }

    public String getPathImage() {
        ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
        return servletContext.getRealPath("") + File.separator + "temp" + File.separator + "photocam" + File.separator;
    }

    public void oncapture(CaptureEvent captureEvent) {
        filename = searching + "_ori";
        byte[] data = captureEvent.getData();

        String newFileName = getPathImage() + filename + ".png";

        try {
            FileImageOutputStream imageOutput;
            imageOutput = new FileImageOutputStream(new File(newFileName));
            imageOutput.write(data, 0, data.length);
            imageOutput.close();

            filename = TEMP_PHOTO_CAM + filename + ".png?rd=" + getRandomImageName();

            allowCrop = true;
        } catch (Exception e) {
            LOGGER.error(e.toString());
            throw new FacesException("Error in writing captured image.", e);
        }

        executeJavaScript("PF('blogui').hide()");
    }

    public void crop() {
        if (croppedImage == null) {
            return;
        }

        newImageName = searching + "_crop";

        String newFileName = getPathImage() + newImageName + ".png";


        FileImageOutputStream imageOutput;
        try {
            imageOutput = new FileImageOutputStream(new File(newFileName));
            imageOutput.write(croppedImage.getBytes(), 0, croppedImage.getBytes().length);
            imageOutput.close();

            newImageName = combineImage(newImageName + ".png") + "?rd=" + getRandomImageName();

            allowCombine = true;

        } catch (Exception e) {
            LOGGER.error("", e);
            addError("Cropping failed.");
        }

        addInfo("Cropping finished.");
    }

    @Override
    public void resetForm() {

    }

    /**
     * @return the regPhoto
     */
    public StreamedContent getRegPhoto() {
        return regPhoto;
    }

    /**
     * @return the searching
     */
    public String getSearching() {
        return searching;
    }

    /**
     * @param searching the searching to set
     */
    public void setSearching(String searching) {
        this.searching = searching;
    }

    /**
     * @return the allowCapture
     */
    public boolean isAllowCapture() {
        return allowCapture;
    }

    /**
     * @param allowCapture the allowCapture to set
     */
    public void setAllowCapture(boolean allowCapture) {
        this.allowCapture = allowCapture;
    }

    /**
     * @return the studentInfo
     */
    public StudentInfo getStudentInfo() {
        return studentInfo;
    }

    /**
     * @param studentInfo the studentInfo to set
     */
    public void setStudentInfo(StudentInfo studentInfo) {
        this.studentInfo = studentInfo;
    }

    /**
     * @return the studentInfoService
     */
    public StudentInfiService getStudentInfoService() {
        return studentInfoService;
    }

    /**
     * @param studentInfoService the studentInfoService to set
     */
    public void setStudentInfoService(StudentInfiService studentInfoService) {
        this.studentInfoService = studentInfoService;
    }

    /**
     * @return the gennericService
     */
    public GennericService<StudentInfo> getGennericService() {
        return gennericService;
    }

    /**
     * @param gennericService the gennericService to set
     */
    public void setGennericService(GennericService<StudentInfo> gennericService) {
        this.gennericService = gennericService;
    }

    /**
     * @param combindWithOutBG the combindWithOutBG to set
     */
    public void setCombindWithOutBG(String combindWithOutBG) {
        this.combindWithOutBG = combindWithOutBG;
    }

    /**
     * @return the combindWithOutBG
     */
    public String getCombindWithOutBG() {
        return combindWithOutBG;
    }

    private AttributedString getAttributeGf(String fName, Font font) {
        AttributedString as = new AttributedString(fName);
        as.addAttribute(TextAttribute.FONT, font);
        as.addAttribute(TextAttribute.FOREGROUND, Color.black);

        return as;
    }

//    private String createBarCode(BigDecimal barcodeText) throws FileNotFoundException, IOException {
//        //Create the barcode bean
//        Code39Bean bean = new Code39Bean();
//
//        final int dpi = 80;
//
////Configure the barcode generator
//        bean.setModuleWidth(UnitConv.in2mm(1.0f / dpi)); //makes the narrow bar 
//        //width exactly one pixel
//        bean.setWideFactor(3);
//        bean.doQuietZone(false);
//        bean.setModuleWidth(0.7);
//
////Open output file
//        String barCode = getPathImage()+"bar_"+barcodeText+".png";
//        File outputFile = new File(barCode);
//        OutputStream out = new FileOutputStream(outputFile);
//        try {
//            //Set up the canvas provider for monochrome PNG output 
//            BitmapCanvasProvider canvas = new BitmapCanvasProvider(
//                    out, "image/x-png", dpi, BufferedImage.TYPE_BYTE_BINARY, false, 0);
//
//            //Generate the barcode
//            bean.generateBarcode(canvas, String.valueOf(barcodeText.toBigInteger()));
//
//            //Signal end of generation
//            canvas.finish();
//        } finally {
//            out.close();
//        }
//        
//        return barCode;
//    }
    private String createBarCode(BigDecimal barcodeText) throws Exception {

        String barCode = getPathImage() + "bar_" + barcodeText + ".png";

        File outputFile = new File(barCode);
        try (OutputStream out = new FileOutputStream(outputFile)) {
            //Set up the canvas provider for monochrome PNG output 
//            BitmapCanvasProvider canvas = new BitmapCanvasProvider(
//                    out, "image/x-png", dpi, BufferedImage.TYPE_BYTE_BINARY, false, 0);

            //Generate the barcode
//            bean.generateBarcode(canvas, String.valueOf(barcodeText.toBigInteger()));
            Barcode barcode = BarcodeFactory.createCode39(barcodeText.toString(), false);
            barcode.setBarWidth(6);
            barcode.setDrawingText(false);
            barcode.setBarHeight(110);
            BarcodeImageHandler.saveJPEG(barcode, outputFile);
            //Signal end of generation
//            canvas.finish();
        }

        return barCode;
    }
    //700px
//    private void setGraphics(Graphics g, BufferedImage image, BufferedImage overlay, BufferedImage imageBarCode, StudentInfo studentInfo, Font tahamaFont) {
//        int x = 90;
//        int y = 45;
//        AttributedString asName = getAttributeGf(studentInfo.getPrefix() + " " + studentInfo.getFName() + " " + studentInfo.getLName(), tahamaFont);
//        AttributedString asNo = getAttributeGf(String.valueOf(studentInfo.getStudentID()), tahamaFont);
//        AttributedString asClass = getAttributeGf(String.valueOf(studentInfo.getClassName()), tahamaFont);
//        AttributedString asFactory = getAttributeGf("คณะ " + String.valueOf(studentInfo.getFacultyName()), FONT13);
//        AttributedString asMajor = getAttributeGf("สาขาวิชา " + String.valueOf(studentInfo.getMajorName()), FONT13);
//        AttributedString expDate = getAttributeGf("Exp : " + String.valueOf(dateTH(studentInfo.getExp(), "dd/MM/yyyy")), tahamaFont);
//        
//        g.drawImage(image, 0, 0, null);
//        g.drawImage(overlay, 240, y,(overlay.getWidth()/2),(overlay.getHeight()/2), null);
//        g.drawImage(imageBarCode, x, y+125, null);
//        //Student Name
//        g.drawString(asName.getIterator(), x, y+10);
//        //No
//        g.drawString(asNo.getIterator(), x, y+30);
//        //Class
//        g.drawString(asClass.getIterator(), x, y+50);
//        //asFactory
//        g.drawString(asFactory.getIterator(), x, y+70);
//        //Major
//        g.drawString(asMajor.getIterator(), x, y+90);
//        //Exp Date
//        g.drawString(expDate.getIterator(), x, y+118);
//    }

    //1000px
    private void setGraphics(Graphics g, BufferedImage image, BufferedImage overlay, BufferedImage imageBarCode, StudentInfo studentInfo, Font tahamaFont) {
        int x = 405;
        int y = 45;
        int margin = 95;
        int startMargin = 245;
        AttributedString asName = getAttributeGf(studentInfo.getPrefix() + " " + studentInfo.getFName() + " " + studentInfo.getLName(), tahamaFont);
        AttributedString asNo = getAttributeGf(String.valueOf(studentInfo.getStudentID()), tahamaFont);
        AttributedString asClass = getAttributeGf(String.valueOf(studentInfo.getClassName()), tahamaFont);
        AttributedString asFactory = getAttributeGf("" + String.valueOf(studentInfo.getFacultyName()), FONT13);
        AttributedString asMajor = getAttributeGf("" + String.valueOf(studentInfo.getMajorName()), FONT13);
        AttributedString expDate = getAttributeGf("Exp : " + String.valueOf(dateTH(studentInfo.getExp(), "dd/MM/yyyy")), tahamaFont);

        g.drawImage(image, 0, 0, null);
        g.drawImage(overlay, 1133, 190, null);
        g.drawImage(imageBarCode, x, startMargin + (margin * 5) + 95, null);
        //Student Name
        g.drawString(asName.getIterator(), x, startMargin);
        //No
        g.drawString(asNo.getIterator(), x, startMargin + (margin * 1));
        //Class
        g.drawString(asClass.getIterator(), x, startMargin + (margin * 2));
        //asFactory
        g.drawString(asFactory.getIterator(), x, startMargin + (margin * 3));
        //Major
        g.drawString(asMajor.getIterator(), x, startMargin + (margin * 4));
        //Exp Date
        g.drawString(expDate.getIterator(), x, startMargin + (margin * 5));
    }

    //Ori px
//    private void setGraphics(Graphics g, BufferedImage image, BufferedImage overlay, BufferedImage imageBarCode, StudentInfo studentInfo, Font tahamaFont) {
//        int x = 270;
//        int y = 45;
//        int margin = 70;
//        AttributedString asName = getAttributeGf(studentInfo.getPrefix() + " " + studentInfo.getFName() + " " + studentInfo.getLName(), tahamaFont);
//        AttributedString asNo = getAttributeGf(String.valueOf(studentInfo.getStudentID()), tahamaFont);
//        AttributedString asClass = getAttributeGf(String.valueOf(studentInfo.getClassName()), tahamaFont);
//        AttributedString asFactory = getAttributeGf("คณะ " + String.valueOf(studentInfo.getFacultyName()), FONT13);
//        AttributedString asMajor = getAttributeGf("สาขาวิชา " + String.valueOf(studentInfo.getMajorName()), FONT13);
//        AttributedString expDate = getAttributeGf("Exp : " + String.valueOf(dateTH(studentInfo.getExp(), "dd/MM/yyyy")), tahamaFont);
//        
//        g.drawImage(image, 0, 0, null);
//        g.drawImage(overlay, 484, 90, null);
//        g.drawImage(imageBarCode, x, 155+(margin*6), null);
//        //Student Name
//        g.drawString(asName.getIterator(), x, 155);
//        //No
//        g.drawString(asNo.getIterator(), x, 155+margin);
//        //Class
//        g.drawString(asClass.getIterator(), x, 155+(margin*2));
//        //asFactory
//        g.drawString(asFactory.getIterator(), x, 155+(margin*3));
//        //Major
//        g.drawString(asMajor.getIterator(), x, 155+(margin*4));
//        //Exp Date
//        g.drawString(expDate.getIterator(), x, 155+(margin*5));
//    }
    /**
     * @return the maxSize
     */
    public String getMaxSize() {
        return maxSize;
    }

    /**
     * @param maxSize the maxSize to set
     */
    public void setMaxSize(String maxSize) {
        this.maxSize = maxSize;
    }

    /**
     * @return the minSize
     */
    public String getMinSize() {
        return minSize;
    }

    /**
     * @param minSize the minSize to set
     */
    public void setMinSize(String minSize) {
        this.minSize = minSize;
    }

    /**
     * @return the initialCoords
     */
    public String getInitialCoords() {
        return initialCoords;
    }

    /**
     * @param initialCoords the initialCoords to set
     */
    public void setInitialCoords(String initialCoords) {
        this.initialCoords = initialCoords;
    }

    /**
     * @return the allowCrop
     */
    public boolean isAllowCrop() {
        return allowCrop;
    }

    /**
     * @param allowCrop the allowCrop to set
     */
    public void setAllowCrop(boolean allowCrop) {
        this.allowCrop = allowCrop;
    }

    /**
     * @return the allowCombine
     */
    public boolean isAllowCombine() {
        return allowCombine;
    }

    /**
     * @param allowCombine the allowCombine to set
     */
    public void setAllowCombine(boolean allowCombine) {
        this.allowCombine = allowCombine;
    }

    private void updateDateStudentCapture() {
        try {
            studentInfo.setImagePath(searching + ".png");
            studentInfo.setCreateBy(getUserAuthen().getUserId());
            studentInfo.setCreateDateTime(new Date());
            gennericService.edit(studentInfo);
            
            LOGGER.debug("studentInfo : {}",studentInfo);
            
            addInfo("บันทึกข้อมูลสำเหร็จ!!");

            searching = null;

            reset();
        } catch (Exception ex) {

            LOGGER.error("Cannot update image : ", ex);

            addError("เกิดข้อผิดพลาด : ", ex.getMessage());

        }
    }

    /**
     * @return the editMode
     */
    public boolean isEditMode() {
        return editMode;
    }

    /**
     * @param editMode the editMode to set
     */
    public void setEditMode(boolean editMode) {
        this.editMode = editMode;
    }

}
